Quake MAP Specs Last Updated: 10/27/96 10:43PM EST *NOTE THIS IS A DRAFT VERSION AND IS UNFINISHED* Info on entities/maps and maintenance by Niklata (Nicholas Kain) Additions and original HTMLization by Thomas Winzig Here are the MAP file specs. This document should tell you everything you need to know about MAP files. This should help you in making editors/building MAP files. If you find an error, or figure something out that I don't know, please email Niklata. I'll put in your contribution and you'll get your name in here as well. This document is now a part of the Unoffical Quake Specs. This standalone version is here to provide you with the most up-to-date information about Quake Map Editing. It is also a part of the Quake Documentation Project. Since map editing is quite untested, a great deal of new information is pouring in about editing Quake levels. Not everything is here yet. I frequently update the seperate Map Specs and you can get the latest version from Quake Technical Resources. Hopefully when editing becomes more mainstream and the rate of new discoveries comes to a near stop, I won't have to tell you about (or maintain) the standalone file. You can get the most up-to-date version of the Quake MAP Specs from Quake Technical Resources. If you place a link to the Quake Map Specs on your webpage, I would strongly request that you also place a link to Quake Technical Resources. ---------------------------------------------------------------------------- Table of Contents Section 1: MAP Information 1.1: Coordinate System 1.2: Brushes 1.3: Map Structure Section 2: Entity Information 2.1: Entity Overview 2.2: Flags and Spawnflags Key 2.3: Optional parameters for triggers 2.4: General entity syntax 2.5: General entity list Section 3: Entity classname examples 3.1: Lights 3.2: Player movement keys 3.3: Movers (Doors, plats, etc) 3.4: Triggers/Switches 3.5: Traps/Things harmful to you 3.6: Miscellaneous Section 4: Special entity-related structures 4.1: Moving platforms 4.2: Monsters and triggers 4.3: How to use trigger_count 4.4: Teleporting monsters 4.5: Properties of Buttons 4.6: Including predefined models Appendix A: Algorithms and Code examples A.1: Introduction and overview Appendix B: Glossary ---------------------------------------------------------------------------- What's New Fixed flag tags. Contributors to the Map Section Thomas Winzig - Confirmation on the model; key's behavior. HTMLization of original Map Specs doc. Clarified several things. Reorganized the document structure a little bit. Brian Hackert - Info on how to use func_train and path_corner. Told me that targetname and target can have real names for their argument, not just numbers. Remco Stoffer - trigger_counter info, light styles, trap_shooter, some trigger_relay info, teleporting monsters, shootable buttons, and lots of other stuff. Thomas Scherning - Information on the last five brush parameters. Lars Bensmann - Information on using origin with attached brushes, a few bugfixes. Robert Jones - Info on using light key with fires, list of light styles. Marc Fontaine - Correcting the Y-axis in the coord system. Bernd Kreimeier - Correcting rot_angle and texture offsets. Ben Morris - Correcting right/left handed system. Dalias - Correcting several errors in section 2.2.3. Use of model tag in map files. Denis Moeller - List of entites and their keys/flags, difficulty flags, several fixes. Martin Fuchs - Several fixes/additions. Section 1: MAP Information 2.1.1 Coordinate System: Quake uses a standard right-handed (X,Y,Z) coordinate system. If you're not familiar with the reference of "right-handed" to a coordinate system, it basically provides a tactile and visual discription of the mechanics of the system. If you point your fingers towards the positive x-axis and bend your fingers so that your knuckles face the positive y-axis, your thumb will point towards the positive z-axis: ^ z+ | | | | |------------> y+ / / / / Some entities also need to have an angle key that tells the direction it is facing. All angles in Quake are represented using degrees for measurement. The possible values are listed below: 1-360: Normal Angle (360 == east) -1: Up -2: Down 2.1.2 Brushes: Brushes are one of the two primary components of a MAP file. Each brush defines a solid region. Brushes define this region as the intersection of four or more planes. Each plane is defined by three noncolinear points. These points must go in a clockwise orientation: 1--2-----------------> | 3 | | | | | , Each brush statement looks like this: { ( 128 0 0 ) ( 128 1 0 ) ( 128 0 1 ) GROUND1_6 0 0 0 1.0 1.0 ( 256 0 0 ) ( 256 0 1 ) ( 256 1 0 ) GROUND1_6 0 0 0 1.0 1.0 ( 0 128 0 ) ( 0 128 1 ) ( 1 128 0 ) GROUND1_6 0 0 0 1.0 1.0 ( 0 384 0 ) ( 1 384 0 ) ( 0 384 1 ) GROUND1_6 0 0 0 1.0 1.0 ( 0 0 64 ) ( 1 0 64 ) ( 0 1 64 ) GROUND1_6 0 0 0 1.0 1.0 ( 0 0 128 ) ( 0 1 128 ) ( 1 0 128 ) GROUND1_6 0 0 0 1.0 1.0 } That's probably just a bit confusing when you first see it. It defines a rectangular region that extends from (128,128,64) to (256,384,128). Here's what a single line means: ( 128 0 0 ) ( 128 1 0 ) ( 128 0 1 ) GROUND1_6 0 0 0 1.0 1.0 1st Point 2nd Point 3rd Point Texture Now, you're probably wondering what those last five numbers are. I've listed what they do below: x_off - Texture x-offset y_off - Texture y-offset rot_angle - floating point value indicating texture rotation x_scale - scales x-dimension of texture (negative value to flip) y_scale - scales y-dimension of texture (negative value to flip) 2.1.3 General MAP Info: The actual MAP file format is quite simple. It is simply a text file. All Quake editing tools should support either UNIX or DOS text formats, as id's tools do. MAP files are the development format for Quake levels. It is preferred that all editors work with MAP files, as all tools released by id Software also use the MAP file format. A map file is basically un-'compiled' level data. The actual MAP file is totally unusable by Quake itself until it is coverted to a BSP file by a BSP builder such as id Software's QBSP. For a MAP file's lightmaps to be calculated by Quake, the level must also be run through a light builder, such as LIGHT. Otherwise, everything will be displayed at full brightness. Finally, to speed up the level and ensure proper display, visibility lists should be calculated by a program such as VIS. The process for building levels in Quake is quite time-consuming compared to building Doom levels, even on a fast computer. The generalized format for a MAP file is as follows: { entity { brush (optional) } } ... Comments in the MAP file are indicated by a "//" (C++ style comment). Many entity/brush combinations can be put into a map file. All MAP files must contain with a worldspawn entity, usually as the first entry. This entry defines all of the normal brushes that make up the structure of the level. There should be only one worldspawn entity per MAP file. Here's the syntax of the worldspawn class: "classname" "worldspawn" // Tells Quake to spawn the world "wad" "DIRPATH" // tells what graphics (texture) WAD2 file to use. "message" "TITLE" // The title of the level "worldtype" "#" // Describes time of environment (changes appearance/name of keys) // 0 == Medieval (medieval) // 1 == Runic (metal) // 2 == Present (base) "sounds" "#" // Tells the CD player which track to play. "light" "#" // Default light level A simple map file would look like this: { "sounds" "1" "classname" "worldspawn" "wad" "/gfx/base.wad" "worldtype" "0" { ( 128 0 0 ) ( 128 1 0 ) ( 128 0 1 ) GROUND1_6 0 0 0 1.0 1.0 ( 256 0 0 ) ( 256 0 1 ) ( 256 1 0 ) GROUND1_6 0 0 0 1.0 1.0 ( 0 128 0 ) ( 0 128 1 ) ( 1 128 0 ) GROUND1_6 0 0 0 1.0 1.0 ( 0 384 0 ) ( 1 384 0 ) ( 0 384 1 ) GROUND1_6 0 0 0 1.0 1.0 ( 0 0 64 ) ( 1 0 64 ) ( 0 1 64 ) GROUND1_6 0 0 0 1.0 1.0 ( 0 0 128 ) ( 0 1 128 ) ( 1 0 128 ) GROUND1_6 0 0 0 1.0 1.0 } } { "classname" "info_player_start" "origin" "256 384 160" } As you can see, all brushes are contained in entities, even those that make up the main level. The most complex part of MAP files are the entities. They are what the rest of this document are about. Section 2: Entity information 2.2.1 Entity Overview: Entities are the second major component of Quake MAP files. An entity is basically a bit like a thing, but they also function as triggers and as pathmarkers. A entity statement looks like this: { "classname" "light" "origin" "0 128 64" "light" "255" } This is what is called a general entity statement. It is called a general statement because it does not attach to a brush. An attached entity statement looks like this: { "classname" "func_door" "angle" "0" "speed" "16" "targetname" "t1" "sounds" "1" "wait" "16" { ( 128 0 0 ) ( 128 1 0 ) ( 128 0 1 ) GROUND1_6 0 0 0 1.0 1.0 ( 256 0 0 ) ( 256 0 1 ) ( 256 1 0 ) GROUND1_6 0 0 0 1.0 1.0 ( 0 128 0 ) ( 0 128 1 ) ( 1 128 0 ) GROUND1_6 0 0 0 1.0 1.0 ( 0 384 0 ) ( 1 384 0 ) ( 0 384 1 ) GROUND1_6 0 0 0 1.0 1.0 ( 0 0 64 ) ( 1 0 64 ) ( 0 1 64 ) GROUND1_6 0 0 0 1.0 1.0 ( 0 0 128 ) ( 0 1 128 ) ( 1 0 128 ) GROUND1_6 0 0 0 1.0 1.0 } } Attached entity brushes can have an "origin" key. It can be used to offset where they appear in the level. For the rest of the document, when I give you frameworks for a structure, the individual entries can be in any order, and lots are optional. I try to mark if an entry is optional, although this has not yet been rigorously tested. In a "" block, your choices for that block are delimited by commas. 2.2.2 Flags and Spawnflags Key: The spawnflags change the default behavior of an entity. They can be set manually using a spawnflags key, or by using flags in the entity. Values can be combined by addition or bitwise or (really the same thing). Spawnflags are also automatically manipulated when you use a flag parameter within the entity. This only has an effect at the progs level though. ** UNDER CONSTRUCTION ** General flags/values: 256 - Does not appear if skill == 0 (easy) 512 - Does not appear if skill == 1 (medium) 1024 - Does not appear if skill == 2 (hard and nightmare) 1792 - Does not appear if skill == 0, 1, 2 (deathmatch games only) 2048 - Does not appear if deathmatch != 0 (in deathmatch games) ammo items: "big" (1) - Doubles amount of ammo in box monsters: "ambush" (1) - Monster only wakes up on sight func_episodegate: "e1" - Appears if player has Episode 1 sigil "e2" - Appears if player has Episode 2 sigil "e3" - Appears if player has Episode 3 sigil "e4" - Appears if player has Episode 4 sigil func_door: "toggle" (1) - "start_open" (2) - "door_dont_link" (4) - "gold_key" (8) - "silver_key" (16) - item_health: "rotten" (1) - Gives 10HP "megahealth" (2) - Gives 100HP, then slowly decrease to max health limit item_sigil: "e1" - Sigil for Episode 1 "e2" - Sigil for Episode 2 "e3" - Sigil for Episode 3 "e4" - Sigil for Episode 4 monster_zombie: "crucified" (1) - Crucified Zombie trigger_teleport: "silent" (2) - 2.2.3 General Entity syntax: (Thanks to John Wakelin who wrote much of this section) The entities define the monsters, things, but also the positions in space where something must happen, so they are the Quake equivalent of both the THINGS and the LINEDEF types from DOOM. The entity definitions are made up of a series of specific details (called keys) that define what each is, where it starts, when it appears etc. Each key is followed by a modifier that arguments it. A key that does not have an argument is called a flag. Its presence alters the behavior of the entity that contains it. Flags are usually only work with certain entity classes. All definitions have the classname key that identifies that entity. The classname keys relate intimately with the code lump and are the names of functions written in Quake C. Key Args Description -------------------------------------------------------------------------------- "classname" "name" // Type of entity to be defined (mandatory) "origin" "X Y Z" // Coordinates of where it starts in space. "angle" "#" // Direction it faces or moves (sometimes in degrees) "light" "#" // Used with the light classname. "target" "t#" // Matches a targetname. "targetname" "t#" // Like a linedef key. "killtarget" "#" // Removes target when triggered? "spawnflags" "#" // Used to flag/describe an entity that is not default. "style" "#" // Used to flag/describe an entity that is not default. "message" "string" // Message displayed when triggered (\n for linebreaks) "mangle" "X Y Z" // Point where the intermission camera looks at {MODEL INFO} // In entities that describe triggers/doors/platforms, etc, // the model info is inserted into the entity brackets, // delimited by another set of brackets. The model key // may be used in place of an inline model declaration. "model" "*#" // Defines the model contained within the brush specifics/args present only in models: "speed" "#" // How fast the model is moved. "wait" "#" // How long a pause between completion of movement or // return to original position (in seconds or 10ths) "lip" "#" // Amount a button/door sticks out when activated. "dmg" "#" // How much damage the model causes when it shuts on you? "health" "#" // How much damage the model takes before it triggers "delay" "#" // Time before event is triggered "sounds" "#" // Sound entity makes when triggered/spawned "wad" "wadfile" // The wad2 graphics file used by the world for textures. "height" "#" // How high a platform will raise --------------------------------------------------------------------------------- { "key1" "arg1" // The first descriptors (usually classname) "key2" "arg2" // The second ... // Etc... { // for entities like doors/triggers/platforms/etc } } Note: The term model refers to a combination of a brush and an entity. One or more brushes are bound to an entity, which controls the behavior of the brushes. All brushes are contained within models. The model numbers in the compiled BSP (*x) comes from the order in which the models are stored in the models structure. These numbers are originally derived from the order of the models in the source MAP file. The worldspawn model is a bounding box that defines the extents of the whole world. There should only be one worldspawn model per map. The models are defined by a bounding box of the max and min(x,y,z). Therefore they are always parallel to the horizontal planes. This bounding box is simply used for speeding up collision detection and will not affect the movement of the models themselves. 2.2.4 All known entities (current for Registered Quake 1.01): air_bubbles : Rising bubbles ambient_comp_hum : Computer background sounds ambient_drip : Dripping sound ambient_drone : Engine/machinery sound ambient_fluoro_buzz : Flourescent buzzing sound ambient_light_buzz : Buzzing sound from light ambient_suck_wind : Wind sound ambient_swamp1 : Frogs croaking ambient_swamp2 : Slightly different sounding frogs croaking ambient_thunder : Thunder sound event_lightning : Lightning (Used to kill Cthon, shareware boss) func_bossgate : Entity appears unless player has all four sigils func_button : A button func_dm_only : A teleporter that only appears in deathmatch func_door : Door func_door_secret : A door that is triggered to open func_episodegate : Entity appears if player has appropriate episode sigil func_illusionary : Creates brush that appears solid, but isn't func_plat : A lift/elevator func_train : A platform (moves along a "train") func_wall : Changes texture to alternate texture when triggered info_intermission : Cameras positioning for intermission (?) info_notnull : Used as a positional target for lighting (does not remove itself) info_null : Used as a positional target for spotlights (removes itself) info_player_coop : A coop player start (more than one allowed) info_player_deathmatch : A deathmatch start (more than one allowed) info_player_start : Main player starting point (only one allowed) info_player_start2 : Return point from episode info_teleport_destination : Gives coords for a teleport destination using a targetname All item_ keys may have a target key. It triggers the event when the item is picked up. item_armor1 : Green armor item_armor2 : Yellow armor item_armorInv : Red armor item_artifact_envirosuit : Environmental Protection Suit item_artifact_invisibility : Ring of Shadows (Invisibility) item_artifact_invulnerability : Penkeyram of Protection item_artifact_super_damage : Quad Damage item_cells : Ammo for the Thunderbolt item_health : Medkit item_key1 : Silver Key item_key2 : Gold Key item_rockets : Ammo for Rocket/Grenade Launcher item_shells : Ammo for both Shotgun and SuperShotgun item_sigil : Sigil (a rune) item_spikes : Ammo for Perforator and Super Perforator item_weapon : Generic weapon class - DO NOT USE light : A projected light. No visible lightsource. light_flame_large_yellow : Large yellow fire (gives off light) light_flame_small_yellow : Small yellow fire (gives off light) light_flame_small_white : Small white fire (gives off light) light_fluoro : A projected light. No visible lightsource. Makes humming sound. light_fluorospark : A projected light. No visible lightsource. Makes broken, sparking sound light_globe : Light that appears as a globe sprite light_torch_small_walltorch : Small wall torch (gives off light) monster_army : Grunt (30HP) monster_boss : Cthon - only can be killed by event_lightning monster_demon1 : Fiend [Demon] (300HP) monster_dog : Attack dog (25HP) monster_enforcer : Enforcer (80HP) monster_fish : Rotfish (25HP) monster_hell_knight : Hell Knight (250HP) monster_knight : Knight (75HP) monster_ogre : Ogre (200HP) monster_ogre_marksman : Ogre [synonymous with monster_ogre] (200HP) monster_oldone : Shubb-Niggurath (40000HP) - requires a misc_teleportrain and an info_intermission monster_shalrath : Shalrath [Vore] (400HP) monster_shambler : Shambler (600HP) - rockets 1/2 damage monster_tarbaby : Spawn [Tarbaby] (80HP) monster_wizard : Scragg [Wizard] (80HP) monster_zombie : Zombie (60HP) misc_explobox : Large Nuclear Container misc_explobox2 : Small Nuclear Container misc_fireball : Small fireball (gives off light, harms player) misc_noisemaker : Makes lots of sounds (not very useful) misc_teleporttrain : Spiked ball needed to telefrag monster_oldone noclass : Prints a warning message when spawned and removes itself path_corner : Used to define path of func_train platforms and of monsters test_fodder : Testing only - DO NOT USE test_teleport : Teleporter Testing - DO NOT USE trap_shooter : Fires nails without needing to be triggered. trap_spikeshooter : Shoots spikes (nails) trigger_changelevel : Changes to another level trigger_counter : Triggers action after it has been triggered count times. trigger_hurt : Hurts whatever touches the trigger trigger_monsterjump : Causes triggering monster to jump in a direction trigger_multiple : Triggers action (can be retriggered) trigger_once : Triggers action only once trigger_onlyregistered : Triggers only if game is registered (registered == 1) trigger_push : Pushes a player in a direction (like a windtunnel) trigger_relay : Allows delayed/multiple actions from one trigger trigger_secret : Triggers action and awards secret credit. trigger_setskill : Changes skill level trigger_teleport : Teleport (all trigger_ keys are triggered by walkover) weapon_grenadelauncher : Grenade Launcher weapon_lightning : Lightning Gun weapon_nailgun : Perforator weapon_rocketlauncher : Rocket Launcher weapon_supernailgun : Super Perforator weapon_supershotgun : Super Shotgun Section 3: Entity 'class' examples 2.3.1 Lights For all light-emmitting entities, spawnflags and style have special meanings: Spawnflags: 0 - Light starts on. Switches off when triggered. 1 - Light starts off. Switches on when triggered. Style: 0 - normal 1 - flicker (first variety) 2 - slow strong pulse 3 - candle (first variety) 4 - fast strobe 5 - gentle pulse 6 - flicker (second variety) 7 - candle (second variety) 8 - candle (third variety) 9 - slow strobe 10 - flourescent flicker 11 - slow pulse, not fading to black styles 32-62 are assigned by the light program for switchable lights 63 - testing Regular Light: { "classname" "light" "origin" "X Y Z" // Tells where the light is "light" "#" // Tells how bright the light is (optional - default 200) "style" "#" // How the light appears "spawnflags" "#" // State light starts in "target" "#" // What the light points at (optional - makes a spotlight) "targetname" "#" // Target id of the light "starts_off;quot; // If present, light starts turned off } Fluorescent Light: { "classname" "light_fluoro" "origin" "X Y Z" // Tells where the light is "light" "#" // Tells how bright the light is (optional - default 200) "style" "#" // How the light appears "spawnflags" "#" // State light starts in "targetname" "#" // Target id of the light } Fluorescent Light (makes sparking sound): { "classname" "light_fluorospark" "origin" "X Y Z" // Tells where the light is "light" "#" // Tells how bright the light is (optional - default 200) "style" "#" // How the light appears "spawnflags" "#" // State light starts in "targetname" "#" // Target id of the light } Torches: { "classname" "light_torch_small_walltorch" "origin" "X Y Z" // Tells where the light is "light" "#" // Tells how bright the light is (optional - default 200) "style" "#" // How the light appears "spawnflags" "#" // State light starts in "targetname" "#" // Target id of the light } Fire: { "classname" "light_flame_large_yellow" "light" "#" // Tells how bright the light is (optional) "origin" "X Y Z" } { "classname" "light_flame_small_yellow, light_flame_small_white" "light" "#" // Tells how bright the light is (optional) "origin" "X Y Z" "starts_off" // If present, light is off until triggered } 2.3.2 Player Movement Entities Level Change Trigger (attaches to brush): { "classname" "trigger_changelevel" "map" "mapname" // Map to change to on trigger; if not present, map is restarted "spawnflags" "#" // Flags describing the object (optional) "no_intermission" // If present, intermission screen is skipped { } } Teleport Trigger (attaches to brush): { "classname" "trigger_teleport" "target" "t#" // Teleport destination name to teleport to. "targetname" "t#" // if present, only teleports when triggered, not when touched (optional) "player_only" // If present, only players can use teleport "silent" // If present, teleport makes no sound (broken in QuakeC; use spawnflags == 2) { { } Teleport Destination: { "classname" "info_teleport_destination" "origin" "X Y Z" "angle" "#" // angle the player will face upon leaving teleport "targetname" "t#" // Teleport's trigger name } 2.3.3 Movers Door (attaches to brush): { "classname" "func_door" "angle" "#" // opening angle "speed" "#" // speed of movement (100 default)(optional) "targetname" "#" // Door's trigger name (optional) "sounds" "#" // sound it makes // 0 = no sound // 1 = stone // 2 = base // 3 = stone chain // 4 = screechy metal "wait" "#" // delay before closing (3 default, -1 never return) (optional) "spawnflags" "#" // Flags describing the object (optional) "lip" "#" // amount remaining at end of move (8 default) (optional) "message" "#" // message printed if door is opened by trigger "health" "#" // if set, door must be shot open "dmg" "#" // damage inflicted on blocking entities "toggle" // door waits in both open and closed states for trigger "start_open" // door starts open; when triggered, closes "door_dont_link" // does not link action to multiple door brushes? "gold_key" // door requires a gold key to open "silver_key" // door requires a silver key to open { } } Secret Door - automatically shootable: { "classname" "func_door_secret" "angle" "#" // angle it moves when activated "speed" "#" // speed of movement "targetname" "#" // Door's trigger name "sounds" "#" // sound it makes "wait" "#" // delay before closing "spawnflags" "#" // Flags describing the object (optional) "lip" "#" // some kind of offset (optional) "open_once" // once open, stays open "1st_left" // first move is left of arrow "1st_down" // first move is down from arrow "no_shoot" // only opened by trigger "always_shoot" // even if targeted, keep shootable { } } Just a regular wall, unless targeted, then changes texture to alternate texture. Also useful for creating deathmatch/single-player only brushes. (attaches to brush): { "classname" "func_wall" "spawnflags" "#" // difficulty level/mode brush appears/does not appear in. { } } A platform (i.e. lift or elevator, attaches to brush) note - The platform should be placed at its top position when you place it in your map. The platform is lowered by the height key. When the plat is stepped on, the plat raises to its original position. To make a platform that starts out at its top position and lowers to the ground, use func_door: { "classname" "func_plat" "height" "#" // determines amount plat moves manually (optional) "speed" "#" // moving speed (default:150) "sounds" "#" // sound it makes (optional) // 1 = base fast // 2 = chain slow { } } Moving platform (Attaches to brush): { "classname" "func_train" "sounds" "#" // Sound it makes when activated // 1 == ratchet metal "speed" "#" // Speed at which it moves (default:100) "target" "t#" // Trigger name of its first path_corner destination "targetname" "t#" // Its trigger name "dmg" "#" // Damage done on crush (default:2) { } } Describes path of train/monsters: { "classname" "path_corner" "origin" "X Y Z" "target" "t#" // Trigger name of next train destination. "targetname" "t#" // It's trigger name. } Appears as solid wall, but can be walked through, light passes through: { "classname" "func_illusionary" { } } 2.3.4 Triggers/Switches A button/switch (attaches to brush): { "classname" "func_button" "angle" "#" // Angle button moves? "speed" "#" // Speed it moves in? "target" "t#" // Trigger name of target entity "health" "#" // If there is health, button is shootable "killtarget" "#" // Kills target when activated "lip" "#" // Amount button sticks out when activated (default:4) "sounds" "#" // Sound it makes when activated // 1 == Steam Metal // 2 == Wooden Clunk // 3 == Metallic Click // 4 == In-Out "wait" "#" // Wait until retrigger? (-1 stays pressed) "delay" "#" // Delay before action is triggered { } } Trigger - removes itself when triggered: { "classname" "trigger_once" "killtarget" "t#" // Kills something [for triggering monster events] (optional) "target" "t#" // Trigger name of target "sounds" "#" // Sound made when triggered // 1 == Secret Sound // 2 == Beep Beep // 3 == Large Switch // 4 == Set "message" to text string "delay" "#" // Delay before action is triggered "health" "#" // if > 1, must be killed to trigger, if == 0, walk-over trigger "message" "#" // String displayed when triggered "notouch" // Only triggered by other entities, not by touching { } } Trigger - can be triggered multiple times: { "classname" "trigger_multiple" "killtarget" "t#" // Kills something [for triggering monster events] (optional) "target" "t#" // Trigger name of target "sounds" "#" // Sound made when triggered // 1 == Secret Sound // 2 == Beep Beep // 3 == Large Switch // 4 == Set "message" to text string "wait" "#" // Delay before retrigger "delay" "#" // Delay before action is triggered "health" "#" // if > 1, must be killed to trigger, if == 0, walk-over trigger "message" "#" // String displayed when triggered "notouch" // Only triggered by other entities, not by touching { } } Trigger - only triggers if console variable registered == 1: { "classname" "trigger_onlyregistered" "killtarget" "t#" // Kills something [for triggering monster events] (optional) "target" "t#" // Trigger name of target "sounds" "#" // Sound made when triggered // 1 == Secret Sound // 2 == Beep Beep // 3 == Large Switch // 4 == Set "message" to text string "delay" "#" // Delay before action is triggered "health" "#" // if > 1, must be killed to trigger, if == 0, walk-over trigger "message" "#" // String displayed when registered == 0 "notouch" // Only triggered by other entities, not by touching { } } Walk-over trigger - can be triggered multiple times: { "classname" "trigger_secret" "killtarget" "t#" // Kills something [for triggering monster events] (optional) "target" "t#" // Trigger name of target "sounds" "#" // Sound made when triggered // 1 == Secret Sound // 2 == Beep Beep "wait" "#" // Delay before retrigger "delay" "#" // Delay before action is triggered "health" "#" // if > 1, must be killed to trigger, if == 0, walk-over trigger "message" "#" // String displayed when triggered "notouch" // Only triggered by other entities, not by touching { } } Triggers target after it is triggered count times: { "classname" "trigger_counter" "targetname" "t#" // Its trigger name "target" "t#" // Trigger name of its target "count" "#" // Decrements on each trigger. When 0 activates target. "wait" "#" // Required delay before retrigger "delay" "#" // Delay before action is triggered "nomessage" // If present, no message will be displayed when triggered. { } } Used to stagger events on a trigger: { "classname" "trigger_relay" "origin" "X Y Z" // Where it is located "killtarget" "#" // Removes targeted entity (optional) "targetname" "t#" // Its trigger name "target" "t#" // Trigger name of its target "delay" "#" // Delay before action is triggered } Makes a monster jump when it reaches a brush: { "classname" "trigger_monsterjump" "speed" "#" // Forward velocity of the monster jump "height" "#" // How high the monster jumps "angle" "#" // Angle towards which the monster jumps { } } Damages whatever touches the brush: { "classname" "trigger_hurt" "dmg" "#" // Damage done to touching entity { } } Pushes the player in a direction: { "classname" "trigger_push" "origin" "X Y Z" // Where it is located "speed" "#" // Force of the push "angle" "#" // Direction player is pushed towards (-1=up -2=down, other=normal) "push_once" // Pushes once, then removes itself } 2.3.5 Traps/Things harmful to you: Triggerable Nail-firing trap: { "classname" "trap_spikeshooter" "origin" "X Y Z" "angle" "#" // Angle the trap fires at "targetname" "t#" // Trap's trigger name "spawnflags" "#" // ??? 1024 works "superspike" // If present, fires large spikes "laser" // If present, fires lasers } Constant Nail-firing trap: { "classname" "trap_shooter" "origin" "X Y Z" "angle" "#" // Angle the trap fires at "wait" "#" // Time between shots "spawnflags" "#" // ??? 1024 works "nextthink" "#" // Delay before firing first spike (so shots can be skeygered) "superspike" // If present, fires large spikes "laser" // If present, fires lasers } Fireballs: { "classname" "misc_fireball" "origin" "X Y Z" "speed" "#" // Tells how fast the fireball moves } 2.3.6 Miscellaneous: Cameras for the intermission screen: { "classname" "info_intermission" "origin" "X Y Z" // location of camera "mangle" "X Y Z" // location the camera looks at "angle" "#" // angle of the camera } Setting difficulty level (attaches to brush): { "classname" "trigger_setskill" "message" "#" // Skill level to change to. // 0 == easy // 1 == normal // 2 == hard // 3 == nightmare { } } Lightning used to kill the boss of shareware. I'll figure out how to use it later... I pretty much know how, I just want to test it before I put it here :). From the testing I've done, the lightning produced will not damage a player, however. It probably triggers a script to give the boss character damage. { "classname" "event_lightning" "origin" "X Y Z" // location of lightning (origin?) "targetname" "t#" // It's trigger name } Section 4: Level Structures 2.4.1 Moving Platforms: Creating a moving platform isn't that difficult. First, you must define the brush that will do the moving. Here's an example: { "classname" "func_train" "sounds" "1" "speed" "128" "target" "t1dest1" "targetname" "t1" { ( -768 0 0 ) ( -768 1 0 ) ( -768 0 1 ) GROUND1_6 0 0 0 1.0 1.0 ( -640 0 0 ) ( -640 0 1 ) ( -640 1 0 ) GROUND1_6 0 0 0 1.0 1.0 ( 0 -384 0 ) ( 0 -384 1 ) ( 1 -384 0 ) GROUND1_6 0 0 0 1.0 1.0 ( 0 -256 0 ) ( 1 -256 0 ) ( 0 -256 1 ) GROUND1_6 0 0 0 1.0 1.0 ( 0 0 -256 ) ( 1 0 -256 ) ( 0 1 -256 ) GROUND1_6 0 0 0 1.0 1.0 ( 0 0 -128 ) ( 0 1 -128 ) ( 1 0 -128 ) GROUND1_6 0 0 0 1.0 1.0 } } Now you define each of the path_corners it will travel to. When it reaches a path_corner, it will float to the next path_corner defined in the target key of the path_corner. The platform will start at the path_corner pointed to by the platform's target key. It will continue the loop indefinitely until it reaches a path_corner with a wait key equal to -1. The platform will go through walls to get to its destination. Here is what its path_corners would look like: { "classname" "path_corner" "origin" "0 0 0" "targetname" "t1dest1" "target"" "t1dest2" } { "classname" "path_corner" "origin" "0 128 0" "targetname" "t1dest2" "target"" "t1dest1" } 2.4.2 Monsters and Triggers: *NEW INFO*: Method may be broken. trigger_counter may be required for it to properly work Have you been wondering how you can get events to trigger when a monster dies, as first seen in E1M2 with the demons? Well, it's not too difficult. When you attach a target key to a monster, the monster's death will trigger the event. I believe (not tested) that if other monsters have a targetname key the same as a monster with the target key, the target event will only occur when all monsters with a matching targetname key are dead. The monster with the target key need not have the targetname key. 2.4.3 How to use trigger_count: The trigger_count class is quite an interesting trigger. You know of the area in E1M1 where you have to hit the three switches to open the door? Well, that's done using a trigger_counter. Each of the buttons you hit has its target property set so it points to a trigger_counter. The trigger_counter has its count key set to three. Each time a switch is hit, the trigger_counter's count property will decrement by one. When it reaches zero, it will open the door. Each button can only be triggered once as it has a wait of -1. Here's an example given to me by Remco Stoffer: { "classname" "func_door" "targetname" "door2" "target" "light1" "angle" "-1" "wait" "-1" "sounds" "4" "message" "press all buttons" { ( -10 120 0 ) ( -10 80 0 ) ( 10 120 0 ) *slime0 2 0 0 1.000000 1.000000 ( 10 80 0 ) ( 0 80 100 ) ( -10 120 0 ) *slime0 2 0 0 1.000000 1.000000 ( 0 80 100 ) ( -10 80 0 ) ( 0 120 100 ) *slime0 2 0 0 1.000000 1.000000 ( -10 80 0 ) ( 10 80 100 ) ( 10 80 0 ) *slime0 2 0 0 1.000000 1.000000 } } { "classname" "trigger_counter" "count" "3" "targetname" "door1" "target" "door2" "wait" "-1" } { "classname" "func_button" "angle" "0" "wait" "-1" "target" "door1" { ( 180 -200 50 ) ( 180 -180 50 ) ( 200 -180 50 ) tlight11 16 0 0 1.000000 1.000000 ( 180 -200 30 ) ( 200 -200 30 ) ( 200 -180 30 ) tlight11 16 0 0 1.000000 1.000000 ( 200 -180 50 ) ( 180 -180 50 ) ( 200 -180 30 ) tlight11 16 0 0 1.000000 1.000000 ( 180 -180 50 ) ( 180 -200 50 ) ( 180 -180 30 ) tlight11 16 0 0 1.000000 1.000000 ( 180 -200 50 ) ( 200 -200 50 ) ( 180 -200 30 ) tlight11 16 0 0 1.000000 1.000000 ( 200 -200 50 ) ( 200 -180 50 ) ( 200 -200 30 ) tlight11 16 0 0 1.000000 1.000000 } } { "classname" "func_button" "angle" "0" "wait" "-1" "target" "door1" { ( 180 -10 50 ) ( 180 10 50 ) ( 200 10 50 ) +0basebtn 0 0 0 1.000000 1.000000 ( 180 -10 30 ) ( 200 -10 30 ) ( 200 10 30 ) +0basebtn 0 0 0 1.000000 1.000000 ( 200 10 50 ) ( 180 10 50 ) ( 200 10 30 ) +0basebtn 0 0 0 1.000000 1.000000 ( 180 10 50 ) ( 180 -10 50 ) ( 180 10 30 ) +0basebtn 0 0 0 1.000000 1.000000 ( 180 -10 50 ) ( 200 -10 50 ) ( 180 -10 30 ) +0basebtn 0 0 0 1.000000 1.000000 ( 200 -10 50 ) ( 200 10 50 ) ( 200 -10 30 ) +0basebtn 0 0 0 1.000000 1.000000 } } { "classname" "func_button" "angle" "0" "wait" "-1" "target" "door1" { ( 180 180 50 ) ( 180 200 50 ) ( 200 200 50 ) +0basebtn 0 0 0 1.000000 1.000000 ( 180 180 30 ) ( 200 180 30 ) ( 200 200 30 ) +0basebtn 0 0 0 1.000000 1.000000 ( 200 200 50 ) ( 180 200 50 ) ( 200 200 30 ) +0basebtn 0 0 0 1.000000 1.000000 ( 180 200 50 ) ( 180 180 50 ) ( 180 200 30 ) +0basebtn 0 0 0 1.000000 1.000000 ( 180 180 50 ) ( 200 180 50 ) ( 180 180 30 ) +0basebtn 0 0 0 1.000000 1.000000 ( 200 180 50 ) ( 200 200 50 ) ( 200 180 30 ) +0basebtn 0 0 0 1.000000 1.000000 } } 2.4.4 Teleporting Monsters: Unlike in Doom-Engine games, you can precisely teleport monsters into new locations in Quake. To do so, you must first create a out of reach area for the monsters to reside in. Give this area a trigger_teleport key and assign a targetname key to it. Create a teleport_destination where you want the monster to appear. Now, you must create a trigger whose target property points to the trigger_teleport's targetname. When this trigger is activated, the monster in the room will teleport to the teleport_destination. Make sure that there is only one monster per room and one room per teleport_destination. Otherwise, when the teleport is triggered, all the monsters will telefrag each other (like what happens in E1M7 when you win). 2.4.5 Properties of Buttons: The behavior of buttons can be altered in many ways. By default, buttons are activated by pressing them (moving near them). Buttons can be made shootable by giving them a health key. Unless you want to have to shoot the button tons of times, set the health key to "1". If you want to have the button flash when you shoot it, you must include all of the button animation textures in the level. You can just put them on brushes outside the level. On a shootable button, you should use one of the special textures designed for shootable buttons that changes appearance when the button is activated/deactivated. These are the +?shoot textures, and both frames of the texture must be present in the level for the texture on the button to change when its state is changed. 2.4.6 Including predefined models: It is possible to substitute inclusion of actual model definitions with a key that defines a model definiton that has already been declared previously in the map file. This is possible by using the model key. Usually, this key is used only by QBSP in a compiled BSP file, but it can also be used in a map file to directly include the model that belongs to a previously defined entity. Here's the general syntax: { "classname" "origin" "model" "*#" } where '#' is the number of the model being included The origin key in this instance acts as an offset to the model, moving it from its original position to the position defined by the origin key's value. The model key directly substitutes for an inline model declaration. There are several limitations with this approach, however. First, the model being included must be precached. This means that either custom QuakeC progs are required for the level to be usable within Quake, or the model being included must have previously been defined within the map file. The second limitiation is that the number of the models of previously defined entities directly corresponds with their position within the map file - for example, the first defined entity with an inline model definition is model 0, the second entity with an inline model declaration is model 1 and so on. This means that any insertations of new models before a model that is used in a non-inline declaration will change the numbering scheme and therefore cause the level to not function as intended. Appendix A: Algorithms and Code Examples A.1.1 Introduction: **SECTION UNDER CONSTRUCTION** Quake is one of the most mathematically demanding games currently out at this time. This means that creating utilities to deal with Quake's data and levels requires a much better understanding of mathematical concepts than what other games do. Thus, I've put together a list of algorithms useful in dealing with map data. This should save you from having to find these from mathematical textbooks and handbooks, and also from having to derive these equations into a form that is useful. All of the equations here were taken from my QMapEd Quake Map Editor project. You'll need to know a few things before you can use the algorithms I present here. First, I'm talking in C here - and if you don't know C, too bad. I can't write to every language out there. I also assume that you have a basic understanding of space analytic geometry, vectors, and matrix equations. If you don't, this stuff probably won't make any sense. Here are the two equations I use to describe a plane: normal form: ax + by + yz = n general form: Ax + By + Cz + D = 0 Both of these equations share common relationships: a = A b = B c = C n = -D Most of the original equations here were obtained from Engineering Mathematics Handbook by Jan J. Tuma, Ph.D. A.2.1 Plane Passing through Three Points: The following formula will give you the equation of a plane (in normal form) from three noncolinear points. Here's the equation in matrix form: Points: Pi, Pj, Pk - (x,y,z) [yi zi 1] [zi xi 1] [xi yi 1] [xi yi zi] [yj zj 1]x + [zj xj 1]y + [xj yj 1]z = [xj yj zj] [yk zk 1] [zk xk 1] [xk yk 1] [xk yk zk] That may look simple, but the equation is not very useful in that form. Before the equation can be use, the matrices must be expanded. Then, you must solve for d, a, b, and c. Fortunately for you, I've already done the work - it's rather long though, so be ready. structures: typedef struct { double x; double y; double z; } point; variables: point p1 == Pi point p2 == Pj point p3 == Pk equations: I'm going to add a new eq using dot/cross products soon. This one is rather lame and untested. d = -(( p1.pt.y*(p2.pt.z-p3.pt.z) - p2.pt.y*(p1.pt.z-p3.pt.z) + p3.pt.y*(p1.pt.z-p2.pt.z) ) + ( p1.pt.z*(p2.pt.x-p3.pt.x) - p2.pt.z*(p1.pt.x-p3.pt.x) + p3.pt.z*(p1.pt.x-p2.pt.x) ) + ( p1.pt.x*(p2.pt.y-p3.pt.y) - p2.pt.x*(p1.pt.y-p3.pt.y) + p3.pt.x*(p1.pt.y-p2.pt.y) )); a = -((-(p1.pt.x*(p2.pt.y*p3.pt.z-p3.pt.y-p2.pt.z) - p2.pt.x*(p1.pt.y*p3.pt.z-p3.pt.y*p1.pt.z) + p3.pt.x*(p1.pt.y*p2.pt.z-p2.pt.y*p1.pt.z)))+ ( p1.pt.z*(p2.pt.x-p3.pt.x) - p2.pt.z*(p1.pt.x-p3.pt.x) + p3.pt.z*(p1.pt.x-p2.pt.x) ) + ( p1.pt.x*(p2.pt.y-p3.pt.y) - p2.pt.x*(p1.pt.y-p3.pt.y) + p3.pt.x*(p1.pt.y-p2.pt.y) )); b = -((-(p1.pt.x*(p2.pt.y*p3.pt.z-p3.pt.y-p2.pt.z) - p2.pt.x*(p1.pt.y*p3.pt.z-p3.pt.y*p1.pt.z) + p3.pt.x*(p1.pt.y*p2.pt.z-p2.pt.y*p1.pt.z)))+ ( p1.pt.y*(p2.pt.z-p3.pt.z) - p2.pt.y*(p1.pt.z-p3.pt.z) + p3.pt.y*(p1.pt.z-p2.pt.z) ) + ( p1.pt.x*(p2.pt.y-p3.pt.y) - p2.pt.x*(p1.pt.y-p3.pt.y) + p3.pt.x*(p1.pt.y-p2.pt.y) )); c = -((-(p1.pt.x*(p2.pt.y*p3.pt.z-p3.pt.y-p2.pt.z) - p2.pt.x*(p1.pt.y*p3.pt.z-p3.pt.y*p1.pt.z) + p3.pt.x*(p1.pt.y*p2.pt.z-p2.pt.y*p1.pt.z)))+ ( p1.pt.y*(p2.pt.z-p3.pt.z) - p2.pt.y*(p1.pt.z-p3.pt.z) + p3.pt.y*(p1.pt.z-p2.pt.z) ) + ( p1.pt.z*(p2.pt.x-p3.pt.x) - p2.pt.z*(p1.pt.x-p3.pt.x) + p3.pt.z*(p1.pt.x-p2.pt.x) )); A.2.2 Intersection of Three Planes: The following formula will give you the point of intersection of three planes. Here's the equation in matrix form: [D1 B1 C1] [D2 B2 C2] [D3 B3 C3] x = - ---------- [A1 B1 C1] [A2 B2 C2] [A3 B3 C3] [A1 D1 C1] [A2 D2 C2] [A3 D3 C3] y = - ---------- [A1 B1 C1] [A2 B2 C2] [A3 B3 C3] [A1 B1 D1] [A2 B2 D2] [A3 B3 D3] z = - ---------- [A1 B1 C1] [A2 B2 C2] [A3 B3 C3] Derive it yourself for now - I haven't yet had time to derive it into code. Glossary brush - a solid region defined by the intersection of planes entity - an object that defines the properties an object in Quake; defines the way in which the object should be handled in the QuakeC code flag - a key that does not require a value and is automatically translated into a spawnflag parameter by QBSP key - a field of an entity that contains a value that affects the entity's characteristics model - a set of brushes all defined in one block noncolinear - not lying on the same line normal - a line perpendicular to a plane plane - the set of all points in a two-dimensional region point - a specific zero-dimensional position in space value - the data assigned to a key ---------------------------------------------------------------------------- The Quake Map Specs are ©1996 Nicholas Kain. Quake is ©1996 id Software. Some information about entities was obtained from the Unofficial Quake Specs, a truly awesome reference guide to Quake editing. Disclaimer: This document is provided as is and may not be perfect. I do not guarentee the validity of any of the information in it. I will not be held liable or responsible for any damages caused from use or misuse of the information contained within this document.